import os

from flask import Blueprint, request, jsonify, session, render_template
from openai import OpenAI

from models import db
from models.ScoreWeight import ScoreWeight
from models.AIInterview import AIInterview
from models.InterviewScores import InterviewScores
from models.Application import Application
from models.Applicant import Applicant
from models.Job import Job
from decimal import Decimal
import re
import json
from datetime import datetime

from flask import session

from openai import OpenAI
import os
from models import db
from models.AIInterview import AIInterview
from models.Application import Application
from models.Job import Job
from models.Resume import Resume
from models.ScoreWeight import ScoreWeight
from models.InterviewScores import InterviewScores
import json
from routes.text_speech_synthesis import *



AIInterview_bp = Blueprint('AIInterview', __name__)

class ConversationManager:
    def __init__(self):
        self.conversation_log = []

    def get_conversation(self):
        return self.conversation_log

    def set_conversation(self, conversation_log):
        self.conversation_log = conversation_log

    def update_conversation(self, new_message):
        self.conversation_log=new_message

conversation_manager = ConversationManager()


job_info_json = None

# 初始化 OpenAI 客户端
client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 面试官系统提示词

system_prompt = """
【指令】你作为专业AI面试官，严格按以下规则生成面试问题：

【输入数据】
1. 职位要求：{position_info}
2. 候选人简历：{resume_info}

【生成规则】
1. 面试流程分三个阶段一共10轮递进式提问：
   - 第1阶段：技术能力验证（聚焦岗位核心技术栈）（5 轮技术能力验证问题）
   - 第2阶段：行为模式评估（考察团队协作与问题解决） （3 轮行为模式评估问题）
   - 第3阶段：认知水平测试（评估学习能力与发展潜力）（2 轮认知水平测试问题）

2. 问题生成要求：
   • 每轮只生成1个最核心问题
   • 问题必须结合候选人的项目经历/技能证书/实习经历/工作经历或者职位要求
   • 使用"追问式"结构（如：您在XX项目中提到...请具体说明...）
   • 禁止任何解释性文字，仅返回问题本身
   • 用户表达准备好了就开始面试
   

3. 评分维度映射（仅用于后台计算，不显示给用户）：
   - 技术深度（40%） | 学习敏锐度（20%） 
   - 协作效能（15%） | 解决方案质量（15%） | 表达逻辑（10%）

【输出格式】
仅返回标准中文问题文本，不要序号、换行等格式，不要返回多余内容，不要告诉用户目前属于第几轮面试，不要有任何注释，只返回文本信息

当前面试阶段：[未开始]
"""

# system_prompt = """
# 你是一名专业严谨的 AI 面试官，需完成以下任务：
#
# 【角色设定】
# 1. 面试分为三个阶段：
#    - **技术面试**（5 道技术问题）
#    - **行为面试**
#    - **总结反馈**
# 2. 你需要根据以下信息精准生成问题：
#    - **职位要求**：{position_info}
#    - **候选人简历**：{resume_info}
# 3. **评分标准（满分 100 分）**：
#    - **技术能力**：掌握岗位相关技术的深度与广度
#    - **学习能力**：学习新技能、适应新环境的能力
#    - **团队协作**：与团队配合、推动项目的能力
#    - **问题解决**：分析问题、制定解决方案的能力
#    - **沟通表达**：清晰阐述观点、有效沟通的能力
#
# 【对话规则】
# 1. **每次只提问 1 个问题**，避免信息过载。
# 2. **问题间保持逻辑连贯**，逐步深入评估候选人能力。
# 3. **面试总共 3 轮**，达到 3 轮后自动结束。
# 4. **用中文提问**，语气专业但友好。
#
# 【输出格式要求】
# 直接返回问题
# """


# 评估报告生成提示词

EVALUATION_PROMPT = """
请基于面试对话历史，生成**结构化评估报告**，对候选人的五项核心能力评分，并提供详细的评估理由。

【输入数据】
面试记录：
{history}
岗位要求：
{position}

【评估标准】
1. 按百分制评分（总分 100 分）。
2. 五个核心维度（分别评分，并提供 50 字左右的评估依据）：
   - 技术能力：候选人对核心技术的掌握程度，能否解决岗位相关的技术问题。
   - 学习能力：是否具备快速学习新技术和适应新环境的能力。
   - 团队协作：是否能与团队成员高效协作，展现出良好的团队精神。
   - 问题解决：是否能够清晰分析问题，并提出合理的解决方案。
   - 沟通表达：表达是否清晰、有逻辑，能否准确传达信息。

【输出 JSON 格式】
{{
  "evaluation_details": [
    {{"dimension": "技术能力", "score": {{score}}, "reason": "..."}},
    {{"dimension": "学习能力", "score": {{score}}, "reason": "..."}},
    {{"dimension": "团队协作", "score": {{score}}, "reason": "..."}},
    {{"dimension": "问题解决", "score": {{score}}, "reason": "..."}},
    {{"dimension": "沟通表达", "score": {{score}}, "reason": "..."}}
  ]
}}
"""


# OpenAI 流式对话

def stream_chat(messages):
    """
    流式聊天功能，逐步接收和处理聊天回复。

    该函数通过调用深度学习模型来生成对给定聊天消息的回复。它以流式处理的方式接收回复内容，
    从而可以逐步处理和显示回复，而不需要等待整个回复生成完毕。

    参数:
    messages (list): 包含聊天消息的列表。每个消息都是一个字典，包含角色（如用户或助手）和消息内容。

    返回:
    str: 助手的回复内容。
    """
    # 初始化回复内容为空字符串
    answer_content = ""

    # 创建聊天流，使用指定的模型和消息进行回复生成
    stream = client.chat.completions.create(
        model="qwen-plus",
        messages=messages,
        stream=True
    )

    # 遍历流中的每个数据块
    for chunk in stream:
        # 检查数据块是否包含选择信息
        if not getattr(chunk, 'choices', None):
            continue

        # 获取数据块中的delta信息，即增量内容
        delta = chunk.choices[0].delta

        # 检查delta是否包含内容属性
        if not hasattr(delta, 'content'):
            continue

        # 检查delta的内容是否非空
        if not getattr(delta, 'content', None):
            continue

        # 将delta的内容累加到回复内容中
        answer_content += delta.content

    # 返回完整的回复内容
    return answer_content

# 解析简历 & 岗位信息

def analyze_resume(resume_id, job_id):
    """
    根据简历ID和工作ID分析简历并获取工作详情。

    参数:
    resume_id (int): 简历的唯一标识符。
    job_id (int): 工作的唯一标识符。

    返回:
    tuple: 包含工作详情字典和解析后的简历数据。
    """
    # 查询数据库以获取指定ID的简历
    resume = Resume.query.filter_by(resume_id=resume_id).first()
    # 查询数据库以获取指定ID的工作
    job = Job.query.filter_by(job_id=job_id).first()

    # 构建工作详情字典，包含工作的重要信息
    job_details = {
        'title': job.title,
        'job_type': job.job_type,
        'description': job.description,
        'requirements': job.requirements,
        'min_salary': job.min_salary,
        'max_salary': job.max_salary
    }

    # 返回工作详情和简历的解析数据
    return job_details, resume.parsed_data

# 生成评估报告
def generate_evaluation_report(history, position_info):
    """
    根据历史记录和职位信息生成评估报告。

    该函数通过格式化提示模板来构造评估提示，然后将其作为消息发送以获取评估报告。
    它尝试从响应中提取并解析 JSON 数据，如果成功则返回 JSON 字符串。

    参数:
    history (str): 会话历史记录，用于构造评估提示。
    position_info (str): 职位相关信息，用于构造评估提示。

    返回:
    str: 提取的 JSON 格式的评估报告字符串，如果提取失败则抛出异常。
    """
    # 构造评估提示消息
    evaluation_message = EVALUATION_PROMPT.format(
        history=history,
        position=position_info
    )
    # 初始化消息列表，包含一条系统角色的消息，内容为评估提示
    messages = [{"role": "system", "content": evaluation_message}]

    # 获取原始响应
    raw_response = stream_chat(messages)

    # 尝试提取 JSON 部分
    try:
        # 查找第一个 { 和最后一个 } 的位置
        start_idx = raw_response.find('{')
        end_idx = raw_response.rfind('}') + 1

        # 如果找到了开始和结束的位置
        if start_idx != -1 and end_idx != -1:
            # 提取 JSON 字符串
            json_str = raw_response[start_idx:end_idx]
            # 验证是否为有效的 JSON
            json.loads(json_str)
            # 返回验证过的 JSON 字符串
            return json_str
        else:
            # 如果未找到有效的 JSON 格式，抛出异常
            raise ValueError("未找到有效的 JSON 格式")

    except (json.JSONDecodeError, ValueError) as e:
        # 解析 JSON 失败时打印错误信息和原始响应，并重新抛出异常
        print(f"解析评估报告失败: {str(e)}")
        print(f"原始响应: {raw_response}")
        raise

def handle_start_interview(application_id):
    """
    处理开始面试的逻辑。

    本函数尝试从会话中获取或创建面试记录，准备面试所需的简历和职位信息，
    初始化面试对话，并生成第一个面试问题。
    """
    try:
        # 这里是开始面试的逻辑
        print(f"Starting interview for application_id: {application_id}")
        # 设置会话标志，表示面试已经开始
        session[f'interview_started_{application_id}'] = True
        print(session)

        # 初始化会话存储
        # if 'conversation_log' not in session:
        #     session['conversation_log'] = []
        # conversation_log = session['conversation_log']
        conversation_log=[]

        # 检查是否已有进行中的面试
        existing_interview = AIInterview.query.filter_by(
            application_id=session['application_id'],
            end_time=None
        ).first()

        if existing_interview:
            # 如果有未完成的面试，继续使用该记录
            session['interview_id'] = existing_interview.interview_id
            # emit('interview_status', {'status': 'continued', 'interview_id': existing_interview.interview_id})
            print('interview_status', {'status': 'continued', 'interview_id': existing_interview.interview_id})

        else:
            # 创建新的面试记录
            new_interview = AIInterview(
                application_id=session['application_id'],
                start_time=datetime.now()
            )
            db.session.add(new_interview)
            db.session.commit()

            session['interview_id'] = new_interview.interview_id
            # emit('interview_status', {'status': 'started', 'interview_id': new_interview.interview_id})
            print('interview_status', {'status': 'started', 'interview_id': new_interview.interview_id})

        # 查询 Application 表
        application = Application.query.filter_by(application_id=session['application_id']).first()
        if not application:
            # emit('error', {'message': '未找到对应的申请记录'})
            print('error', {'message': '未找到对应的申请记录'})
            return

        # 获取简历和职位信息
        job_info_json, resume_json = analyze_resume(application.resume_id, application.job_id)
        session['job_info_json'] = job_info_json  # 保存到session

        # 初始化面试对话
        initial_message = system_prompt.format(
            position_info=job_info_json,
            resume_info=resume_json,
            current_round=1
        )

        # 初始化会话历史
        conversation_log = [
            {"role": "system", "content": initial_message},
            {"role": "user", "content": "我准备好了，面试开始"}
        ]
        # session['conversation_log'] = conversation_log
        session.modified = True  # 确保session被标记为已修改

        # 生成第一个问题
        answer = stream_chat(conversation_log)
        conversation_log.append({"role": "assistant", "content": answer})
        # session['conversation_log'] = conversation_log
        # session.modified = True

        # emit('new_message', {'role': 'assistant', 'content': answer})
        print('new_message', {'role': 'assistant', 'content': answer})
        return answer, conversation_log

    except Exception as e:
        db.session.rollback()
        # emit('error', {'message': f'开始面试失败: {str(e)}'})
        print('error', {'message': f'开始面试失败: {str(e)}'})
        return

def handle_user_input(data,conversation_log):
    try:
        # 从session获取会话历史
        if conversation_log is None:
            # emit('error', {'message': '面试会话未初始化'})
            print('error', {'message': '面试会话未初始化'})
            return
        conversation_log = conversation_log

        # user_input = data.get('content')
        user_input = data
        conversation_log.append({"role": "user", "content": user_input})
        # session['conversation_log'] = conversation_log
        # session.modified = True

        # 计算当前轮次
        current_round = (len(conversation_log) - 2) // 2
        if current_round == 0:
            current_round = 1

        # 检查是否达到最大轮次
        max_rounds = 10
        if current_round == max_rounds:
            handle_end_interview(application_id=session['application_id'], conversation_log=conversation_log)
            return "面试已结束，感谢您的参与！", conversation_log

        answer = stream_chat(conversation_log)
        conversation_log.append({"role": "assistant", "content": answer})
        # session['conversation_log'] = conversation_log
        # session.modified = True

        # emit('new_message', {'role': 'assistant', 'content': answer})
        print('new_message', {'role': 'assistant', 'content': answer})
        return answer,conversation_log

    except Exception as e:
        # emit('error', {'message': f'处理回答失败: {str(e)}'})
        print('error', {'message': f'处理回答失败: {str(e)}'})

def handle_end_interview(application_id,conversation_log):
    conversation_log= conversation_log

    print(2222)
    # 获取对话历史
    history = "\n".join([f"{msg['role']}: {msg['content']}" for msg in conversation_log[2:]])

    # 从session获取job_info_json
    job_info_json = session.get('job_info_json')
    if not job_info_json:
        # emit('error', {'message': '面试信息丢失'})
        print('error', {'message': '面试信息丢失'})
        return

    # 生成评估报告
    evaluation_report = generate_evaluation_report(history, job_info_json)
    print(evaluation_report)

    try:
        # 解析评估报告 JSON
        evaluation_data = json.loads(evaluation_report)
        print(evaluation_data)

        # 获取面试记录
        interview_id = session.get('interview_id')
        interview = AIInterview.query.get(interview_id)

        if interview:
            # 更新面试记录
            interview.history = history
            interview.evaluation = evaluation_data
            interview.end_time = datetime.now()

            # 获取评分并确保类型转换为 float
            scores = {}
            for item in evaluation_data['evaluation_details']:
                dimension = item['dimension']
                # 确保分数是浮点数类型
                score = float(item['score'])
                if dimension == '技术能力':
                    scores['technical_ability'] = score
                elif dimension == '学习能力':
                    scores['learning_ability'] = score
                elif dimension == '团队协作':
                    scores['team_collaboration'] = score
                elif dimension == '问题解决':
                    scores['problem_solving'] = score
                elif dimension == '沟通表达':
                    scores['communication_expression'] = score

            print(scores)
            # 验证分数范围
            for score_value in scores.values():
                if not (0 <= score_value <= 100):
                    raise ValueError(f"分数必须在0-100范围内: {score_value}")

            # 使用 ORM 模型创建分数记录，确保类型正确
            interview_scores = InterviewScores(
                interview_id=int(interview_id),  # 确保是整数
                technical_ability=float(scores['technical_ability']),
                learning_ability=float(scores['learning_ability']),
                team_collaboration=float(scores['team_collaboration']),
                problem_solving=float(scores['problem_solving']),
                communication_expression=float(scores['communication_expression'])
            )

            db.session.add(interview_scores)

            # 获取公司权重设置
            application = Application.query.get(interview.application_id)
            job = Job.query.get(application.job_id)
            company_weights = ScoreWeight.query.filter_by(company_id=job.company_id).first()

            # 设置权重并确保转换为浮点数
            if not company_weights:
                weights = {
                    'technical_weight': 0.40,
                    'learning_weight': 0.20,
                    'team_weight': 0.15,
                    'problem_solving_weight': 0.15,
                    'communication_weight': 0.10
                }
            else:
                weights = {
                    'technical_weight': float(company_weights.technical_weight),
                    'learning_weight': float(company_weights.learning_weight),
                    'team_weight': float(company_weights.team_weight),
                    'problem_solving_weight': float(company_weights.problem_solving_weight),
                    'communication_weight': float(company_weights.communication_weight)
                }

            # 计算总分
            overall_score = float(
                scores['technical_ability'] * weights['technical_weight'] +
                scores['learning_ability'] * weights['learning_weight'] +
                scores['team_collaboration'] * weights['team_weight'] +
                scores['problem_solving'] * weights['problem_solving_weight'] +
                scores['communication_expression'] * weights['communication_weight']
            )

            # 更新总分
            interview.overall_score = overall_score

            # 提交所有更改
            db.session.commit()

            # 在评估报告发送之后，更新申请状态
            try:
                # 更新 Application 状态
                application = Application.query.get(interview.application_id)
                if application:
                    application.status = '待定'
                    db.session.commit()

                # 发送评估报告和结束通知给前端
                # emit('evaluation_report', {
                #     'report': evaluation_report,
                #     'overall_score': overall_score,
                #     'status': 'completed'  # 添加状态标识
                # })
                print('evaluation_report', {
                    'report': evaluation_report,
                    'overall_score': overall_score,
                    'status': 'completed'  # 添加状态标识
                })


            except Exception as e:
                db.session.rollback()
                # emit('error', {'message': f'更新申请状态失败: {str(e)}'})
                print('error', {'message': f'更新申请状态失败: {str(e)}'})
                return

            # 清理session中的会话数据
            session.pop('job_info_json', None)
            session.pop('interview_started_8', None)
            session.pop('interview_id', None)
            session.modified = True
            session[f'interview_ended_{application_id}'] = True

            return  # 终止对话

        else:
            # emit('error', {'message': '未找到面试记录'})
            print('error', {'message': '未找到面试记录'})

    except ValueError as e:
        db.session.rollback()
        # emit('error', {'message': f'数据类型错误: {str(e)}'})
        print('error', {'message': f'数据类型错误: {str(e)}'})

        return
    except Exception as e:
        db.session.rollback()
        # emit('error', {'message': f'保存评估结果失败: {str(e)}'})
        print('error', {'message': f'保存评估结果失败: {str(e)}'})
        return

    # 清理session中的会话数据
    # session.pop('conversation_log', None)
    session.pop('job_info_json', None)
    session.modified = True

    return  # 终止对话


def process_chat_history(history):
    """
    处理聊天记录字符串，将其分割成独立的消息，并返回一个包含所有消息的列表。

    :param history: 包含聊天记录的字符串
    :return: 包含所有独立消息的列表
    """
    if not history:
        return []

    # 分割对话记录为单独的消息
    messages = []
    current_message = ''
    lines = history.split('\n')
    i = 0

    while i < len(lines):
        line = lines[i].strip()

        if not line:  # 跳过空行
            i += 1
            continue

        if line.startswith('assistant:'):  # 处理面试官消息
            # 找到最后一个 } 的位置
            message_lines = []
            while i < len(lines):
                current_line = lines[i].strip()
                if not current_line:
                    i += 1
                    continue
                message_lines.append(current_line)
                if '}' in current_line:
                    # 找到最后一个}后的内容
                    last_brace = current_line.rindex('}')
                    remaining_text = current_line[last_brace + 1:].strip()
                    if remaining_text:
                        message_lines = [remaining_text]
                    else:
                        message_lines = []
                i += 1
                if i < len(lines) and (lines[i].strip().startswith('user:') or lines[i].strip().startswith('assistant:')):
                    break
            if message_lines:
                messages.append(' '.join(message_lines))

        elif line.startswith('user:'):  # 处理用户消息
            # 直接获取user:后的内容
            content = line[5:].strip()  # 跳过"user:"五个字符
            if content:
                messages.append(content)
            i += 1

        else:
            i += 1

    return messages


@AIInterview_bp.route('/interview_report/<int:application_id>')
def interview_report(application_id):
    # 获取面试记录和相关联的应用信息
    interview = (
        db.session.query(AIInterview, Application, Applicant, Job)
        .join(Application, AIInterview.application_id == Application.application_id)
        .join(Applicant, Application.applicant_id == Applicant.applicant_id)
        .join(Job, Application.job_id == Job.job_id)
        .filter(AIInterview.application_id == application_id)
        .first()
    )
    
    if not interview:
        return jsonify({'error': '未找到面试记录'}), 404
    
    interview_obj, application, applicant, job = interview
    
    # 处理对话记录
    processed_history = process_chat_history(interview_obj.history)
    
    # 准备数据
    report_data = {
        'interview_id': interview_obj.interview_id,
        'start_time': interview_obj.start_time,
        'end_time': interview_obj.end_time,
        'history': processed_history,  # 处理后的对话记录
        'evaluation': interview_obj.evaluation,  # 评估报告
        'overall_score': interview_obj.overall_score,
        'application': {
            'candidate_name': applicant.full_name,
            'job_title': job.title,
            'application_id': application.application_id
        }
    }
    
    return render_template('company/interview_report.html', report=report_data)

@AIInterview_bp.route('/get_interview_report', methods=['GET'])
def get_interview_report():
    application_id = request.args.get('application_id')
    if not application_id:
        return jsonify({'error': '缺少必要参数'}), 400
        
    interview = (
        db.session.query(AIInterview)
        .filter(AIInterview.application_id == application_id)
        .first()
    )
    
    if not interview:
        return jsonify({'error': '未找到面试记录'}), 404
    
    # 处理对话记录
    processed_history = process_chat_history(interview.history)
        
    return jsonify({
        'success': True,
        'data': {
            'evaluation': interview.evaluation,
            'history': processed_history,
            'overall_score': interview.overall_score
        }
    })




@AIInterview_bp.route('/avatar/chat',methods=['POST'])
def avatar_chat():
    conversation_log=conversation_manager.get_conversation()


    data = request.json
    query = data['query']

    print(query)
    application_id = session.get('application_id')
    print(application_id)
    print(session)

    # print(session)
    # 检查会话中是否已经开始了面试

    if not session.get(f'interview_started_{application_id}'):
        print(123)

        session['num']=1
        # 如果面试未开始，则调用 handle_start_interview 函数
        first_question,conversation_log= handle_start_interview(application_id=application_id)

        conversation_manager.update_conversation(conversation_log)

        vioceToSpeech(first_question,session['num'])
       # timestamp = int(time.time())
        tempName=f"/static/audio/temp{session['num']}.mp3"
        result = {
            "audio": tempName,#替换第一次回答的语音
            "blendshapes": '',
            "audio_offsets": '',
            'text': first_question
        }
        return result


    # if session.get(f'interview_ended_{application_id}'):
    #     num = session['num']
    #     num = num + 1
    #     session['num'] = num
    #     vioceToSpeech("面试已结束，感谢您的参与！", session['num'])
    #     # 如果面试已结束，则返回面试结束消息
    #     tempName = f"/static/audio/temp{session['num']}.mp3"
    #     result = {
    #         "audio": tempName,#面试结束
    #         "blendshapes": '',
    #         "audio_offsets": '',
    #         'text': '面试已结束，感谢您的参与！'
    #     }
    #     return result

    num=session['num']
    num=num+1
    session['num']=num

    question,conversation_log=handle_user_input(data=query,conversation_log=conversation_log)
    conversation_manager.update_conversation(conversation_log)

    if session.get(f'interview_ended_{application_id}'):
        vioceToSpeech("面试已结束，感谢您的参与！", session['num'])
        # 如果面试已结束，则返回面试结束消息
        tempName = f"/static/audio/temp{session['num']}.mp3"
        result = {
            "audio": tempName,  # 面试结束
            "blendshapes": '',
            "audio_offsets": '',
            'text': '面试已结束，感谢您的参与！'
        }
        return result


    vioceToSpeech(question,session['num'])
    print(question)
    tempName = f"/static/audio/temp{session['num']}.mp3"
    result = {
        "audio": tempName,#语音转文字
        "blendshapes": '',
        "audio_offsets": '',
        'text': question
    }

    # result={}
    # result['audio_offsets'] = ""
    # audio_relative_path = reply.content[len(TmpDir.tmp_root_path()):]
    # result['audio'] = f'/audios{"" if audio_relative_path[0] == "/" else "/"}{audio_relative_path}'
    # result['blendshapes'] = voice_engine.blend_shapes

    return result


